import imaplib
import email
import re
import arrow
from src.config.config import app_config
from email.header import decode_header
from src.dingding.dingding import del_dingding_task
from src.util.log import log
from src.db.ticket import TicketDao, Ticket
from typing import Optional


def decoded_payload(payload, charset):
    try:
        return payload.decode(charset)
    except UnicodeDecodeError:
        try:
            return payload.decode('utf-8')
        except UnicodeDecodeError:
            return payload.decode('latin1')


def fetch_email(imap, email_id):
    status, data = imap.fetch(email_id, '(RFC822)')
    msg = email.message_from_bytes(data[0][1])
    subject, encoding = decode_header(msg["Subject"])[0]
    if isinstance(subject, bytes):
        subject = subject.decode(encoding or 'utf-8', errors='replace')

    text_content = ""
    if msg.is_multipart():
        for part in msg.walk():
            if part.get_content_type() == "text/plain":
                payload = part.get_payload(decode=True)
                charset = part.get_content_charset()
                text_content = decoded_payload(payload, charset)
                break
            if part.get_content_type() == "text/html":
                payload = part.get_payload(decode=True)
                charset = part.get_content_charset()
                text_content = decoded_payload(payload, charset)
                break
    else:
        if msg.get_content_type() == 'text/plain':
            payload = msg.get_payload(decode=True)
            charset = msg.get_content_charset()
            text_content = decoded_payload(payload, charset)
        elif msg.get_content_type() == 'text/html':
            payload = msg.get_payload(decode=True)
            charset = msg.get_content_charset()
            text_content = decoded_payload(payload, charset)

    return subject, text_content


def handle_del_order(text_content):
    try:
        order_no = search_order_no(text_content)

        log(f"删除订单：{order_no}")
        ticket = TicketDao.del_ticket(order_no)
        if ticket:
            log(f"订单号：{ticket.order_no}]删除成功！")
            if del_dingding_task(ticket.dingding_event_id):
                log(f"订单号：{ticket.order_no}，日程：{ticket.dingding_event_id},删除成功！")
    except Exception as e:
        log("删除订单异常了")
        log(e)


def search_order_no(text_content) -> Optional[str]:
    order_no = ""
    try:
        order_no_pattern = fr"{app_config.order_pattern}"
        order_no = re.search(order_no_pattern, text_content)
        order_no = order_no.group() if order_no else None
        log(f"订单号：[{order_no}]")
    except Exception as e:
        log("获取订单号异常")
        log(e)
    return order_no


def handle_pay_order(text_content) -> Optional[Ticket]:
    try:
        order_no = search_order_no(text_content)

        # 定义正则表达式模式
        order_pattern = fr"{app_config.ticket_pattern}"
        # 使用正则表达式搜索文本
        order_info = re.search(order_pattern, text_content)
        order_info = order_info.group(0) if order_info else None
        order_info = order_info.replace(app_config.order_info_replace, "")
        order_info = order_info.replace("电子客票。", "")
        order_info = order_info.replace("成人票", "")
        order_info = order_info.replace("二等座", "")
        order_info = order_info.replace(" ", "").replace("，", ",")
        order_info_list = order_info.split(",")
        order_info_list = [item for item in order_info_list if
                           item != "" and not item.startswith("二等座") and not item.startswith(
                               "票价") and not item.startswith("成人票")]
        log(f"解析到订单信息：{order_info_list}")

        train_number = str(order_info_list[2]).replace("次列车", "")
        log(f"车次：[{train_number}]")
        seat = order_info_list[3]
        log(f"座位：[{seat}]")
        train_entrance = order_info_list[4]
        log(f"检票口：[{train_entrance}]")
        start_place = order_info_list[1].split("-")[0]
        log(f"出发地：[{start_place}]")
        end_place = order_info_list[1].split("-")[1]
        log(f"目的地：[{end_place}]")
        train_arrow = arrow.get(str(order_info_list[0]).replace("开", ""), "YYYY年MM月DD日HH:mm")
        train_start_time = train_arrow.format("HH:mm")
        log(f"出发时间：[{train_start_time}]")
        train_start_date = train_arrow.format("YYYY年MM月DD日")
        log(f"出发日期：[{train_start_date}]")
        if (order_no and train_number and seat and train_entrance and start_place
                and end_place and train_start_time and train_start_date):
            log("数据解析成功！")
            ticket = Ticket()
            ticket.order_no = order_no
            ticket.train_number = train_number
            ticket.seat = seat
            ticket.ticket_entrance = train_entrance
            ticket.start_place = start_place
            ticket.end_place = end_place
            ticket.time = train_start_time
            ticket.date = train_start_date
            return ticket
        else:
            log("数据解析失败！")
            return None
    except Exception as err:
        log("异常了！")
        log(err)
    return None


def run_email_service():
    imap = imaplib.IMAP4_SSL(app_config.imap_host)
    imap.login(app_config.email, app_config.password)
    log(f"开始登录邮箱imap_host:{app_config.imap_host},email:{app_config.email},password:{app_config.password}")
    # 上传客户端身份信息
    imaplib.Commands['ID'] = ('AUTH',)
    args = ("name", "12306", "contact", "XXXX@163.com", "version", "1.0.0", "vendor", "email")
    # noinspection PyProtectedMember
    imap._simple_command('ID', '("' + '" "'.join(args) + '")')

    imap.select("INBOX")
    status, response = imap.search(None, 'ALL')
    email_ids = response[0].split()
    log(f"获取到{len(email_ids)}封邮件:{email_ids}")
    log(f"购票成功邮件标题:{app_config.email_pay_subject}")
    log(f"退票成功邮件标题:{app_config.email_refund_subject}")
    for email_id in email_ids:
        subject, text_content = fetch_email(imap, email_id)
        log(f"邮件id:{email_id},主题:{subject},内容:{text_content}")
        is_handle_pay = False
        for s in app_config.email_pay_subject:
            if subject.__contains__(s):
                is_handle_pay = True
                log("处理购票成功邮件")
                ticket = handle_pay_order(text_content)
                if ticket:
                    TicketDao.insert(ticket)
                break
        if not is_handle_pay:
            for s in app_config.email_refund_subject:
                if subject.__contains__(s):
                    log("处理退票成功邮件")
                    handle_del_order(text_content)
                    break
    imap.close()
    imap.logout()
    log("邮箱退出登录")
